/*
 *  Copyright (c) 2022 Kirky
 * Licensed under the Open Software Licence, Version 3.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://opensource.org/licenses/osl-3.0.php
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.lingeringdream.luciole.helper.hwid;

import com.alibaba.fastjson.JSONObject;
import com.huawei.hms.accountsdk.constant.CommonConstant;
import com.huawei.hms.accountsdk.exception.ApiException;
import com.huawei.hms.accountsdk.support.account.AccountAuthManager;
import com.huawei.hms.accountsdk.support.account.request.AccountAuthParams;
import com.huawei.hms.accountsdk.support.account.request.AccountAuthParamsHelper;
import com.huawei.hms.accountsdk.support.account.result.AuthAccount;
import com.huawei.hms.accountsdk.support.account.service.AccountAuthService;
import com.huawei.hms.accountsdk.support.account.tasks.Task;
import com.lingeringdream.luciole.helper.HttpHelper;
import com.lingeringdream.luciole.helper.PreferencesHelper;
import com.lingeringdream.luciole.model.ApiConstants;
import com.lingeringdream.luciole.model.entity.User;
import ohos.aafwk.ability.AbilityPackage;
import ohos.app.Context;
import ohos.app.dispatcher.TaskDispatcher;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
import okhttp3.MediaType;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

import java.io.IOException;
import java.util.Map;

/**
 * 初始化页面
 *
 * @author Kirky
 * @version 2.0
 * @date 2022/5/5
 */
public final class HuaweiAccountHelper {
    private final HiLogLabel TAG = new HiLogLabel(HiLog.LOG_APP, 0xD001, HuaweiAccountHelper.class.getSimpleName());
    private final int HTTP_STATUS_OK = 200;
    private PreferencesHelper preferencesHelper;

    /**
     * 调用华为帐号SDK的初始化方法AccountAuthManager.init()进行初始化
     *
     * @param abilityPackage 当前应用的AbilityPackage
     */
    public void initHuaweiAccountSdk(AbilityPackage abilityPackage) {
        Task<Void> task;
        try {
            // 调用AccountAuthManager.init方法初始化
            task = AccountAuthManager.init(abilityPackage);
        } catch (ApiException apiException) {
            HiLog.error(TAG, "InitHuaweiAccountSDK exception: "
                    + apiException.getStatusCode()
                    + "; message: "
                    + apiException.getStatusMessage());
            apiException.getStatusCode();
            return;
        }
        task.addOnSuccessListener(v -> {
            //初始化成功
            HiLog.info(TAG, "initHuaweiAccountSDK SUCCESS.");
        });

        task.addOnFailureListener(e -> {
            // SDK初始化失败
            if (e instanceof ApiException) {
                ApiException apiException = (ApiException) e;
                // SDK初始化失败，status code标识了失败的原因
                apiException.getStatusCode();
                HiLog.error(TAG, "InitHuaweiAccountSDK FAILED. statusCode: "
                        + apiException.getStatusCode()
                        + "; message: "
                        + apiException.getStatusMessage());
            }
        });
    }

    /**
     * 华为账号登录
     */
    public void signIn(TaskDispatcher dispatcher, Context context) {
        HiLog.info(TAG, "Init Huawei account auth service START.");
        AccountAuthService accountAuthService;
//        配置登录请求参数AccountAuthParams
        AccountAuthParams accountAuthParams =
                new AccountAuthParamsHelper(AccountAuthParams.DEFAULT_AUTH_REQUEST_PARAM).createParams();
        try {
            accountAuthService = AccountAuthManager.getService(accountAuthParams);
            HiLog.info(TAG, "Init Huawei accountAuthService SUCCESS");
        } catch (ApiException e) {
//             处理初始化登录授权服务失败，status code标识了失败的原因
            e.getStatusCode();
            HiLog.error(TAG, "Init Huawei account AuthService FAILED.");
            return;
        }

//         调用静默登录接口。
        Task<AuthAccount> taskSilentSignIn = accountAuthService.silentSignIn();
        HiLog.info(TAG, "SilentSign START.");
//         添加静默登录成功处理监听
        taskSilentSignIn.addOnSuccessListener(authAccount -> {
            HiLog.info(TAG, "SilentSignIn SUCCESS");
//             静默登录成功，获取AuthorizationCode到服务端
            preferencesHelper = PreferencesHelper.getInstance(context);
            sendAuthorizationCode(authAccount.getAuthorizationCode(), dispatcher);

        });

//         添加静默登录失败监听
        taskSilentSignIn.addOnFailureListener(e -> {
            if (e instanceof ApiException) {
                ApiException apiException = (ApiException) e;
                HiLog.info(TAG, "SilentSignIn FAILED, status code: "
                        + apiException.getStatusCode()
                        + ". Need to foreground sign in");

//                 静默登录失败，显式地调用前台登录授权接口，完成登录授权。
                Task<AuthAccount> taskSignIn = accountAuthService.signIn();
                HiLog.info(TAG, "SignIn foreground START.");
                if (taskSignIn == null) {
                    HiLog.info(TAG, "SignIn foreground task is null.");
                    return;
                }
                taskSignIn.addOnSuccessListener(authAccount -> {
                    HiLog.info(TAG, "SignIn foreground SUCCESS.");
//                     发送授权码到服务器
                    preferencesHelper = PreferencesHelper.getInstance(context);
                    sendAuthorizationCode(authAccount.getAuthorizationCode(), dispatcher);
                });
                taskSignIn.addOnFailureListener(e1 -> {
                    HiLog.error(TAG, "SignIn foreground FAILED.");
                    if (e1 instanceof ApiException) {
                        ApiException apiException1 = (ApiException) e1;
//                         登录失败，status code标识了失败的原因
                        apiException1.getStatusCode();
                        HiLog.error(TAG, "SignIn foreground FAILED. status code: "
                                + apiException1.getStatusCode()
                                + ".");
                        if (CommonConstant.RETCODE.SIGN_IN_CANCELLED == apiException1.getStatusCode()) {
                            HiLog.error(TAG, "Error message: User click CANCEL or Return, user cancel login in.");
                        }
                    }
                });
            }
        });
    }

    /**
     * 华为账号登出
     */
    private void signOut(TaskDispatcher dispatcher) {
        AccountAuthService accountAuthService = null;
        AccountAuthParams accountAuthParams = new AccountAuthParamsHelper(AccountAuthParams.DEFAULT_AUTH_REQUEST_PARAM).setEmail().createParams();
        try {
            accountAuthService = AccountAuthManager.getService(accountAuthParams);
        } catch (ApiException e) {
//             处理初始化登录授权服务失败，status code标识了失败的原因，请参见API参考中的错误码了解详细错误原因
            e.getStatusCode();
            return;
        }
        Task<Void> task = accountAuthService.signOut();
        task.addOnSuccessListener(v -> {
            // 华为帐号登出成功，接入应用处理登出后逻辑
            HiLog.info(TAG, "SignOut SUCCESS.");

        });

        task.addOnFailureListener(e -> {
            // 华为帐号退出失败
            if (e instanceof ApiException) {
                ApiException apiException = (ApiException) e;
                // 华为帐号退出失败，status code标识了失败的原因，请参见API参考中的错误码了解详细错误原因
                // 登录失败，status code标识了失败的原因
                apiException.getStatusCode();
                HiLog.error(TAG, "SignIn foreground FAILED. status code: "
                        + apiException.getStatusCode()
                        + ".");
            }
        });
    }

    /**
     * 将AuthorizationCode发送给服务端
     */
    private void sendAuthorizationCode(String authorizationCode, TaskDispatcher dispatcher) {
//         将AuthorizationCode发送给服务端
        HttpHelper httpHelper = HttpHelper.getInstance(dispatcher);
        JSONObject json = new JSONObject();
        json.put("client_id", ApiConstants.CLIENT_ID);
        json.put("client_secret", ApiConstants.CLIENT_SECRET);
        json.put("grant_type", "authorization_code");
        json.put("code", authorizationCode);

        Request request = new Request.Builder()
                .url(ApiConstants.LOGIN.getApi())
                .header("Content-type", "application/x-www-form-urlencoded")
                .post(RequestBody.create(MediaType.parse("application/x-www-form-urlencoded"), json.toString()))
                .build();
        Map<String,Object> res = httpHelper.synchronousExecute(request);
        if ((int)res.get("code") != HTTP_STATUS_OK) {
//            请求失败
            assert res.get("body") != null;
            json = JSONObject.parseObject((String) res.get("body"));
            HiLog.info(TAG, "error type: " + json.getString("error") +
                    "error_description: " + json.getString("error_description"));
        } else {
//            请求成功
            assert res.get("body") != null;
            json = JSONObject.parseObject((String) res.get("body"));
            preferencesHelper.putSync("access_token", json.getString("access_token"));
            preferencesHelper.putSync("refresh_token", json.getString("refresh_token"));
            preferencesHelper.putSync("expires_in", json.getString("expires_in"));

        }
    }

    /**
     * 获取用户信息
     */
    private void getUserInfo(HttpHelper httpHelper) {
        JSONObject json = new JSONObject();
        json.put("access_token", preferencesHelper.getBoolean("access_token"));
        Request request = new Request.Builder()
                .url(ApiConstants.USER_QUERY.getApi())
                .header("Content-type", "application/json")
                .post(RequestBody.create(MediaType.parse("application/x-www-form-urlencoded"), json.toString()))
                .build();
        Map<String,Object> res = httpHelper.synchronousExecute(request);
        if ((int)res.get("code") != HTTP_STATUS_OK) {
//            请求失败
            assert res.get("body") != null;
            json = JSONObject.parseObject((String) res.get("body"));
            HiLog.info(TAG, "error type: " + json.getString("error") +
                    "error_description: " + json.getString("error_description"));
        } else {
//            请求成功
            assert res.get("body") != null;
            User user = JSONObject.parseObject((String) res.get("body"), User.class);
//                TODO 插入数据库

        }
    }

}